package jwebtester.business.services.impl;

import infrastructure.Scopes;

import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;

import jwebtester.business.services.CompetenciesService;
import jwebtester.dal.provider.CompetenciesDataProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;

import domain.entities.Competency;

/**
 * This concrete implementation uses {@link Scopes#Session} to cache
 * competencies tree
 * 
 * @author tillias
 * 
 */
@Service
@Scope(value = Scopes.Session, proxyMode = ScopedProxyMode.INTERFACES)
public class CompetenciesServiceImpl implements CompetenciesService, Serializable {

	private static final long serialVersionUID = -7912900553461813719L;
	private static final Logger LOG = LoggerFactory.getLogger(CompetenciesServiceImpl.class);

	@Autowired
	private transient CompetenciesDataProvider dataProvider;

	private Competency treeRoot;

	private ConcurrentHashMap<Integer, Boolean> expandedNodesMap;

	private Object locker;

	public CompetenciesServiceImpl() {
		expandedNodesMap = new ConcurrentHashMap<Integer, Boolean>(16, .75f, 3);
		locker = new Object();
	}

	@Override
	public Competency getHierarchy(final int organizationID, final boolean forceRefresh) {
		LOG.trace(String.format("Trying to get cached competency tree for organizationID=%s",
				organizationID));

		if (forceRefresh || treeRoot == null) {

			if (forceRefresh) {
				LOG.trace("Force refresh for competency tree has been called");
			}

			LOG.trace(String.format("Loading competencies tree from db for organizationID=%s",
					organizationID));

			treeRoot = dataProvider.getHierarchy(organizationID);
		}

		return treeRoot;
	}

	@Override
	public ConcurrentHashMap<Integer, Boolean> getExpandedNodesMap() {
		return expandedNodesMap;
	}

	public void setExpandedNodesMap(final ConcurrentHashMap<Integer, Boolean> expandedNodesMap) {
		this.expandedNodesMap = expandedNodesMap;
	}

	public Competency getTreeRoot() {
		return treeRoot;
	}

	public void setTreeRoot(final Competency treeRoot) {
		this.treeRoot = treeRoot;
	}

	public Object getLocker() {
		return locker;
	}

	public void setLocker(final Object locker) {
		this.locker = locker;
	}
}
